Eshan Kaul
We have all heard the countless Bitcoin backers claiming that Bitcoin is a bullet-proof hedge against inflation and is the best way to protect long-term wealth, and recently many established financial institutions have also been hoping onto this bandwagon. Their argument is simple. Bitcoin, unlike normal fiat currencies, has a limited, predetermined supply of coins that can be entered into circulation. This means that governments or central banks can not devalue the currency by increasing the supply. This limited quantity attribute has resulted in many individual and institutional investors liking bitcoin to gold which used to be believed as a hedge against the dollar.
The goal of this project is to determine if there is any validity to the argument that cryptocurrencies can be used as a hedge against inflation. Are cryptocurrencies really a good method of protecting wealth from inflation and if so, do all cryptocurrencies work, or are specific currencies that work better than others. These questions are motivated by the larger questions of how does adjusting the money supply while maintaining the monetary base affects the greater economy, but for the purposes of this project, we will focus on tackling the more specific questions of what are the relationships between crypto and inflation?
To address this issue we would like to collect relevant data on historical and current inflation rates along with data on the price patterns of at least one type of fixed supply cryptocurrency and one type of cryptocurrency with a flexible supply.
The analysis will be broken down into two parts. The first part will compare the current/previous relationship between cryptocurrencies and inflation rates. The second part will then be to develop a model to estimate the future trends of cryptocurrencies and inflation rates to explore how the two might vary in the future.
import pandas as pd
import numpy as np
import requests
import pandas_datareader as pdr
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.graphics.tsaplots import plot_pacf
from statsmodels.tsa.arima_model import ARIMA
import statsmodels.formula.api as smf
from bs4 import BeautifulSoup
import time
import ssl
import json
import matplotlib.pyplot as plt
import plotly.express as px
import seaborn as sns
%matplotlib inline
The following data is retrieved from https://fred.stlouisfed.org/. This website is the online database for the Federal Reserve Economic Data and is used to gather the inflation data, along with any other relevant inflationary metrics. The data is downloaded directly from the FRED website in CSV format, and simple scripts are then run to convert the data to the correct types, and rename the variables/columns for readability.
#FED RESERVE DATA
Federal_Funds_Rate = pd.read_csv("Federal_Funds_Rate.csv")
US_CPI = pd.read_csv("US_CPI.csv")
Inflation_Expectations = pd.read_csv("Inflation_Expectations.csv")
Inflation_ConsumerPrices_US = pd.read_csv("Inflation_ConsumerPricesUS.csv")
inflation = pd.read_csv("MonthlyInflation.csv", index_col = False)
print(Federal_Funds_Rate)
print(US_CPI)
print(Inflation_Expectations)
print(Inflation_ConsumerPrices_US)
print(inflation)
DATE DFF
0 1990-03-01 8.30
1 1990-03-02 8.27
2 1990-03-03 8.27
3 1990-03-04 8.27
4 1990-03-05 8.24
... ... ...
11566 2021-10-30 0.07
11567 2021-10-31 0.07
11568 2021-11-01 0.08
11569 2021-11-02 0.08
11570 2021-11-03 0.08
[11571 rows x 2 columns]
DATE CPIAUCSL
0 1947-01-01 21.480
1 1947-02-01 21.620
2 1947-03-01 22.000
3 1947-04-01 22.000
4 1947-05-01 21.950
.. ... ...
892 2021-05-01 268.551
893 2021-06-01 270.981
894 2021-07-01 272.265
895 2021-08-01 273.012
896 2021-09-01 274.138
[897 rows x 2 columns]
DATE MICH
0 1978-01-01 5.2
1 1978-02-01 6.4
2 1978-03-01 6.3
3 1978-04-01 6.7
4 1978-05-01 6.9
.. ... ...
520 2021-05-01 4.6
521 2021-06-01 4.2
522 2021-07-01 4.7
523 2021-08-01 4.6
524 2021-09-01 4.6
[525 rows x 2 columns]
DATE FPCPITOTLZGUSA
0 1960-01-01 1.457976
1 1961-01-01 1.070724
2 1962-01-01 1.198773
3 1963-01-01 1.239669
4 1964-01-01 1.278912
.. ... ...
56 2016-01-01 1.261583
57 2017-01-01 2.130110
58 2018-01-01 2.442583
59 2019-01-01 1.812210
60 2020-01-01 1.233584
[61 rows x 2 columns]
Inflation
0 2.7
1 2.7
2 2.7
3 2.7
4 2.7
... ...
1419 5.7
1420 5.7
1421 5.7
1422 5.7
1423 5.7
[1424 rows x 1 columns]
Cleaning FRED Data
# Renames the column for clarity
Federal_Funds_Rate.rename(columns = {"DFF" : "FFR"}, inplace = True)
US_CPI.rename(columns = {"CPIAUCSL" : "CPI"}, inplace = True)
Inflation_Expectations.rename(columns = {"MICH" : "Expected_Inflation"}, inplace = True)
Inflation_ConsumerPrices_US.rename(columns = {"FPCPITOTLZGUSA" : "Inflation"}, inplace = True)
# Converts the DATE column data to the pandas datetime object
Federal_Funds_Rate["DATE"] = pd.to_datetime(Federal_Funds_Rate["DATE"])
US_CPI["DATE"] = pd.to_datetime(US_CPI["DATE"])
Inflation_Expectations["DATE"] = pd.to_datetime(Inflation_Expectations["DATE"])
Inflation_ConsumerPrices_US["DATE"] = pd.to_datetime(Inflation_ConsumerPrices_US["DATE"])
# Creates a copy of the dataframe so the original data is kept intact
FFR_df = Federal_Funds_Rate.copy()
US_CPI_df = US_CPI.copy()
Inflation_Expectations_df = Inflation_Expectations.copy()
Inflation_ConsumerPrices_US_df = Inflation_ConsumerPrices_US.copy()
# Creates a dataframe that has the average FFR by year
Average_FFR_Annual = FFR_df.groupby(FFR_df.DATE.dt.year)["FFR"].transform("mean") # list of the average FFR by year
Average_FFR_Annual_DF = pd.DataFrame({"DATE" : FFR_df.DATE, "Anual_FFR" : Average_FFR_Annual})
Average_FFR_Annual_DF.drop_duplicates(subset = ["Anual_FFR"])
Average_FFR_Annual_DF["DATE"] = Average_FFR_Annual_DF["DATE"].dt.year
Average_FFR_Annual_DF = Average_FFR_Annual_DF.drop_duplicates(keep = "first")
Average_FFR_Annual_DF = Average_FFR_Annual_DF.reset_index(drop = True)
Average_FFR_Annual_DF
| DATE | Anual_FFR | |
|---|---|---|
| 0 | 1990 | 8.070229 |
| 1 | 1991 | 5.685014 |
| 2 | 1992 | 3.521066 |
| 3 | 1993 | 3.021342 |
| 4 | 1994 | 4.206329 |
| 5 | 1995 | 5.834301 |
| 6 | 1996 | 5.300464 |
| 7 | 1997 | 5.461507 |
| 8 | 1998 | 5.350932 |
| 9 | 1999 | 4.972356 |
| 10 | 2000 | 6.237432 |
| 11 | 2001 | 3.878356 |
| 12 | 2002 | 1.666795 |
| 13 | 2003 | 1.126493 |
| 14 | 2004 | 1.350328 |
| 15 | 2005 | 3.217068 |
| 16 | 2006 | 4.965425 |
| 17 | 2007 | 5.017315 |
| 18 | 2008 | 1.924180 |
| 19 | 2009 | 0.158603 |
| 20 | 2010 | 0.176247 |
| 21 | 2011 | 0.101507 |
| 22 | 2012 | 0.140574 |
| 23 | 2013 | 0.107342 |
| 24 | 2014 | 0.088493 |
| 25 | 2015 | 0.133726 |
| 26 | 2016 | 0.393197 |
| 27 | 2017 | 1.002959 |
| 28 | 2018 | 1.834932 |
| 29 | 2019 | 2.157260 |
| 30 | 2020 | 0.372240 |
| 31 | 2021 | 0.078502 |
The following data is on the relevant cryptocurrency metrics. These data sets are retrieved from Binance and Coinbase. The Coinbase data is retrieved using a method that is provided by the Coinbase API to retrieve .csv files of their daily data. The method works by passing in a string argument of the cryptocurrency that is being requested and returns the .csv file of the past year's work of data for the specified cryptocurrency. The data that was read in was already cleaned and well named and did not require any additional cleaning scripts to be used for later analysis and visualizations.
#CRYPTO DATA
filepath = "https://www.cryptodatadownload.com/cdd/Binance_BTCUSDT_d.csv"
# adjusts the setting to account for the HTTPS certificate(s)
ssl._create_default_https_context = ssl._create_unverified_context
# Now we want to create a dataframe and use Pandas' to_csv function to read in our file
Binance_BTC = pd.read_csv(filepath, skiprows = 1) # use skiprows to drop frist row which contains the url
Coinbase_ETH_dailydata = pd.read_csv("Coinbase_ETHUSD_dailydata.csv")
Coinbase_BTC_dailydata = pd.read_csv("Coinbase_BTCUSD_dailydata.csv")
print(Binance_BTC)
print(Coinbase_BTC_dailydata)
print(Coinbase_ETH_dailydata)
unix date symbol open high \
0 1.646611e+12 2022-03-07 00:00:00 BTC/USDT 38420.80 38468.67
1 1.646525e+12 2022-03-06 00:00:00 BTC/USDT 39397.97 39693.87
2 1.646438e+12 2022-03-05 00:00:00 BTC/USDT 39148.65 39613.24
3 1.646352e+12 2022-03-04 00:00:00 BTC/USDT 42454.00 42527.30
4 1.646266e+12 2022-03-03 00:00:00 BTC/USDT 43892.99 44101.12
... ... ... ... ... ...
1660 1.503274e+09 2017-08-21 BTC/USDT 4086.29 4119.62
1661 1.503187e+09 2017-08-20 BTC/USDT 4139.98 4211.08
1662 1.503101e+09 2017-08-19 BTC/USDT 4108.37 4184.69
1663 1.503014e+09 2017-08-18 BTC/USDT 4285.08 4371.52
1664 1.502928e+09 2017-08-17 BTC/USDT 4469.93 4485.39
low close Volume BTC Volume USDT tradecount
0 38184.32 38273.38 953.91013 3.656757e+07 21630.0
1 38088.57 38420.81 39677.26158 1.542258e+09 986352.0
2 38407.59 39397.96 30363.13341 1.187690e+09 879727.0
3 38550.00 39148.66 61964.68498 2.527001e+09 1465066.0
4 41832.28 42454.00 50940.61021 2.192152e+09 1289320.0
... ... ... ... ... ...
1660 3911.79 4016.00 685.12000 2.770592e+06 NaN
1661 4032.62 4086.29 463.54000 1.915636e+06 NaN
1662 3850.00 4139.98 371.15000 1.508239e+06 NaN
1663 3938.77 4108.37 1178.07000 4.994494e+06 NaN
1664 4200.74 4285.08 647.86000 2.812379e+06 NaN
[1665 rows x 10 columns]
unix low high open close volume \
0 1640131200 48615.49 49595.00 48914.70 49335.71 2443.539143
1 1640044800 46645.05 49339.31 46926.07 48914.70 15461.410573
2 1639958400 45568.00 47548.93 46687.20 46926.07 16039.385104
3 1639872000 46440.11 48351.92 46857.49 46687.19 9518.707128
4 1639785600 45515.72 47368.73 46159.87 46859.46 8170.853032
.. ... ... ... ... ... ...
295 1614643200 47075.11 50250.00 49635.30 48511.60 17063.563020
296 1614556800 45042.13 49829.00 45231.74 49639.40 25068.250437
297 1614470400 43016.00 46656.00 46169.92 45231.75 22745.606002
298 1614384000 45055.00 48356.86 46319.79 46180.75 16290.280717
299 1614297600 44150.00 48464.64 47063.90 46326.20 36048.618193
date vol_fiat
0 2021-12-22 1.205537e+08
1 2021-12-21 7.562903e+08
2 2021-12-20 7.526653e+08
3 2021-12-19 4.444017e+08
4 2021-12-18 3.828818e+08
.. ... ...
295 2021-03-02 8.277807e+08
296 2021-03-01 1.244373e+09
297 2021-02-28 1.028824e+09
298 2021-02-27 7.522974e+08
299 2021-02-26 1.669995e+09
[300 rows x 8 columns]
unix low high open close volume \
0 1640131200 3995.01 4075.00 4017.35 4053.68 27827.609901
1 1640044800 3908.13 4063.89 3946.59 4017.11 137991.501492
2 1639958400 3754.80 3984.08 3925.78 3946.16 172027.915720
3 1639872000 3886.03 4039.73 3961.93 3925.79 102078.812326
4 1639785600 3768.14 3999.00 3876.37 3961.92 113485.775219
.. ... ... ... ... ... ...
295 1614643200 1455.86 1605.89 1571.87 1488.34 240668.581136
296 1614556800 1412.61 1574.28 1421.80 1571.82 313413.589566
297 1614470400 1292.76 1469.96 1460.49 1422.02 460805.821443
298 1614384000 1420.00 1526.82 1445.09 1460.57 231399.556927
299 1614297600 1400.01 1564.11 1482.05 1445.18 380775.959042
date vol_fiat
0 2021-12-22 1.128042e+08
1 2021-12-21 5.543270e+08
2 2021-12-20 6.788497e+08
3 2021-12-19 4.007400e+08
4 2021-12-18 4.496216e+08
.. ... ...
295 2021-03-02 3.581967e+08
296 2021-03-01 4.926297e+08
297 2021-02-28 6.552751e+08
298 2021-02-27 3.379753e+08
299 2021-02-26 5.502898e+08
[300 rows x 8 columns]
Binance_BTC
| unix | date | symbol | open | high | low | close | Volume BTC | Volume USDT | tradecount | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1.646611e+12 | 2022-03-07 00:00:00 | BTC/USDT | 38420.80 | 38468.67 | 38184.32 | 38273.38 | 953.91013 | 3.656757e+07 | 21630.0 |
| 1 | 1.646525e+12 | 2022-03-06 00:00:00 | BTC/USDT | 39397.97 | 39693.87 | 38088.57 | 38420.81 | 39677.26158 | 1.542258e+09 | 986352.0 |
| 2 | 1.646438e+12 | 2022-03-05 00:00:00 | BTC/USDT | 39148.65 | 39613.24 | 38407.59 | 39397.96 | 30363.13341 | 1.187690e+09 | 879727.0 |
| 3 | 1.646352e+12 | 2022-03-04 00:00:00 | BTC/USDT | 42454.00 | 42527.30 | 38550.00 | 39148.66 | 61964.68498 | 2.527001e+09 | 1465066.0 |
| 4 | 1.646266e+12 | 2022-03-03 00:00:00 | BTC/USDT | 43892.99 | 44101.12 | 41832.28 | 42454.00 | 50940.61021 | 2.192152e+09 | 1289320.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1660 | 1.503274e+09 | 2017-08-21 | BTC/USDT | 4086.29 | 4119.62 | 3911.79 | 4016.00 | 685.12000 | 2.770592e+06 | NaN |
| 1661 | 1.503187e+09 | 2017-08-20 | BTC/USDT | 4139.98 | 4211.08 | 4032.62 | 4086.29 | 463.54000 | 1.915636e+06 | NaN |
| 1662 | 1.503101e+09 | 2017-08-19 | BTC/USDT | 4108.37 | 4184.69 | 3850.00 | 4139.98 | 371.15000 | 1.508239e+06 | NaN |
| 1663 | 1.503014e+09 | 2017-08-18 | BTC/USDT | 4285.08 | 4371.52 | 3938.77 | 4108.37 | 1178.07000 | 4.994494e+06 | NaN |
| 1664 | 1.502928e+09 | 2017-08-17 | BTC/USDT | 4469.93 | 4485.39 | 4200.74 | 4285.08 | 647.86000 | 2.812379e+06 | NaN |
1665 rows × 10 columns
# This method is provided by Coinbase to retrive .csv files of thier daily data from the past year
def fetch_daily_data(symbol):
pair_split = symbol.split('/') # symbol must be passed in as the following format "XXX/XXX" ex."BTC/USD"
symbol = pair_split[0] + '-' + pair_split[1]
url = f'https://api.pro.coinbase.com/products/{symbol}/candles?granularity=86400'
response = requests.get(url)
if response.status_code == 200: # checks the response from server is good
data = pd.DataFrame(json.loads(response.text), columns=['unix', 'low', 'high', 'open', 'close', 'volume'])
data['date'] = pd.to_datetime(data['unix'], unit='s') # convert date for readablility
data['vol_fiat'] = data['volume'] * data['close'] # multiplies crypto volume with closing price to approximate fiat volume
# if data is not recived, print a message to alert no data was returned
if data is None:
print("Did not return any data from Coinbase for this symbol")
# otherwise if data is retrived write to the file
else:
data.to_csv(f'Coinbase_{pair_split[0] + pair_split[1]}_dailydata.csv', index=False)
else:
print("Did not receieve OK response from Coinbase API")
if __name__ == "__main__":
# we set which pair we want to retrieve data for
pair = "BTC/USD"
fetch_daily_data(symbol=pair)
fetch_daily_data("BTC/USD")
fetch_daily_data("ETH/USD")
The following line graphs show the collected data to better understand the data.
Inflation = px.line(Inflation_ConsumerPrices_US_df, x = "DATE", y ="Inflation", title = "Real Inflation Rates")
Inflation.update_xaxes(
rangeslider_visible = True,
rangeselector = dict(
buttons = list([
dict(count = 1, label = "1m", step = "month", stepmode = "backward"),
dict(count = 6, label = "6m", step = "month", stepmode = "backward"),
dict(count = 1, label = "YTD", step = "year", stepmode = "todate"),
dict(count = 1, label = "1y", step = "year", stepmode = "backward"),
dict(step = "all")
])
)
)
Inflation.show()
It is interesting to note that although the real inflation rates seem to be slow-moving and take several years to change in value the public expectations of inflation rates are much more volatile, constantly changing, and often times much more extreme than the actual rates.
expected_inflation = px.line(Inflation_Expectations_df, x = "DATE", y ="Expected_Inflation", title = "Public Inflation Expectations")
expected_inflation.update_xaxes(
rangeslider_visible = True,
rangeselector = dict(
buttons = list([
dict(count = 1, label = "1m", step = "month", stepmode = "backward"),
dict(count = 6, label = "6m", step = "month", stepmode = "backward"),
dict(count = 1, label = "YTD", step = "year", stepmode = "todate"),
dict(count = 1, label = "1y", step = "year", stepmode = "backward"),
dict(step = "all")
])
)
)
expected_inflation.show()
cpi = px.line(US_CPI_df, x = "DATE", y ="CPI", title = "Consumer Price Index Time Series")
cpi.update_xaxes(
rangeslider_visible = True,
rangeselector = dict(
buttons = list([
dict(count = 1, label = "1m", step = "month", stepmode = "backward"),
dict(count = 6, label = "6m", step = "month", stepmode = "backward"),
dict(count = 1, label = "YTD", step = "year", stepmode = "todate"),
dict(count = 1, label = "1y", step = "year", stepmode = "backward"),
dict(step = "all")
])
)
)
cpi.show()
We see here that the closing price data for Bitcoin and Ethereum both seem to have similar movements throughout the year. This connection is worth exploring further with some more analysis.
Coinbase_BTC_dailydata
btc = px.line(Coinbase_BTC_dailydata, x = "date", y ="close", title = "Bitcoin Prices")
btc.update_xaxes(
rangeslider_visible = True,
rangeselector = dict(
buttons = list([
dict(count = 1, label = "1m", step = "month", stepmode = "backward"),
dict(count = 6, label = "6m", step = "month", stepmode = "backward"),
dict(count = 1, label = "YTD", step = "year", stepmode = "todate"),
dict(count = 1, label = "1y", step = "year", stepmode = "backward"),
dict(step = "all")
])
)
)
btc.show()
Coinbase_ETH_dailydata
ETH = px.line(Coinbase_ETH_dailydata, x = "date", y ="close", title = "Ethereum Prices")
ETH.update_xaxes(
rangeslider_visible = True,
rangeselector = dict(
buttons = list([
dict(count = 1, label = "1m", step = "month", stepmode = "backward"),
dict(count = 6, label = "6m", step = "month", stepmode = "backward"),
dict(count = 1, label = "YTD", step = "year", stepmode = "todate"),
dict(count = 1, label = "1y", step = "year", stepmode = "backward"),
dict(step = "all")
])
)
)
ETH.show()
This scatter plot further shows the relationship between the price of Bitcoin and Ethereum. There appears to be a small positive linear correlation between the price of the two cryptocurrencies. This correlation seems to be confirmed by the ordinary least squares regression line shown on the graph. This begs the question if Bitcoin and Ethereum are correlated are other cryptos also correlated. To further explore this a Pearson correlation can be used to measure the linear correlation between the different crypto currencies.
df = pd.DataFrame([Coinbase_BTC_dailydata.date, Coinbase_BTC_dailydata.close, Coinbase_ETH_dailydata.close]).transpose()
df.columns = ["date", "BTC", "ETH"]
scatter_plot = px.scatter(df, x = "BTC", y = "ETH", trendline = "ols", title = "Relationship Between Movement in Crypto Prices")
scatter_plot.show()
df
| date | BTC | ETH | |
|---|---|---|---|
| 0 | 2021-12-22 | 49335.71 | 4053.68 |
| 1 | 2021-12-21 | 48914.7 | 4017.11 |
| 2 | 2021-12-20 | 46926.07 | 3946.16 |
| 3 | 2021-12-19 | 46687.19 | 3925.79 |
| 4 | 2021-12-18 | 46859.46 | 3961.92 |
| ... | ... | ... | ... |
| 295 | 2021-03-02 | 48511.6 | 1488.34 |
| 296 | 2021-03-01 | 49639.4 | 1571.82 |
| 297 | 2021-02-28 | 45231.75 | 1422.02 |
| 298 | 2021-02-27 | 46180.75 | 1460.57 |
| 299 | 2021-02-26 | 46326.2 | 1445.18 |
300 rows × 3 columns
To further explore the relationships between cryptocurrencies and inflation more data will be needed. The first step will then be to gather price data on more cryptocurrencies from the US Federal Reserve online database. This data will then need to be combined with the public's expectation of future inflation rates. The reason the expected inflation rates are used instead of the real inflation rates is that it is assumed that people will believe that crypto is an inflationary hedge and will make their movements based on their future expectations. This heat map shows the Pearson correlation between several different cryptocurrencies (Bitcoin, Ethereum, Litecoin, Bitcoin Cash) and the expected inflation rate.
As seen in the graph, there seems to be some correlation between the different cryptocurrencies, and all crypto except Bitcoin Cash seems to be positively correlated with the expected inflation rates. This on the surface seems to give some validity to the argument that people view cryptocurrencies as an inflationary hedge, as when the public's inflation expectations rise there is a noticeable rise in many crypto prices. This trend is especially noticeable in Bitcoin and Ethereum.
# Bitcoin Ethereum Litecoin Bitcoin Cash
FredCryptoDF = pdr.get_data_fred(["CBBTCUSD", "CBETHUSD", "CBLTCUSD", "CBBCHUSD"])# Reads in crypto data from Federal Reserve Data Base
FredCryptoDF = FredCryptoDF.dropna()
FredCryptoDF = FredCryptoDF.reset_index()
FredCryptoDF["Expected_Inflation"] = inflation.Inflation # combines the expected inflation data with the crypto data
FredCryptoDF = FredCryptoDF.dropna()
display(FredCryptoDF)
plt.figure(figsize = (15,8))
sns.heatmap(FredCryptoDF.corr(), cmap = "bone", linewidths = .7, linecolor = "black", square = True)
FredCryptoDF.corr()
| DATE | CBBTCUSD | CBETHUSD | CBLTCUSD | CBBCHUSD | Expected_Inflation | |
|---|---|---|---|---|---|---|
| 0 | 2017-12-20 | 16496.89 | 802.86 | 305.59 | 3746.84 | 2.7 |
| 1 | 2017-12-21 | 15758.80 | 796.98 | 311.00 | 3162.53 | 2.7 |
| 2 | 2017-12-22 | 14210.57 | 682.11 | 267.79 | 2719.99 | 2.7 |
| 3 | 2017-12-23 | 15075.89 | 732.80 | 293.03 | 3160.00 | 2.7 |
| 4 | 2017-12-24 | 14221.94 | 697.04 | 278.81 | 2919.01 | 2.7 |
| ... | ... | ... | ... | ... | ... | ... |
| 1419 | 2021-11-14 | 65714.05 | 4633.47 | 279.70 | 679.45 | 5.7 |
| 1420 | 2021-11-15 | 63441.68 | 4555.68 | 262.68 | 664.90 | 5.7 |
| 1421 | 2021-11-16 | 60147.32 | 4214.97 | 230.94 | 599.53 | 5.7 |
| 1422 | 2021-11-17 | 60314.28 | 4289.42 | 229.34 | 595.34 | 5.7 |
| 1423 | 2021-11-18 | 57017.38 | 4009.87 | 204.65 | 555.13 | 5.7 |
1424 rows × 6 columns
| CBBTCUSD | CBETHUSD | CBLTCUSD | CBBCHUSD | Expected_Inflation | |
|---|---|---|---|---|---|
| CBBTCUSD | 1.000000 | 0.918331 | 0.751984 | 0.186411 | 0.791498 |
| CBETHUSD | 0.918331 | 1.000000 | 0.764401 | 0.302795 | 0.916008 |
| CBLTCUSD | 0.751984 | 0.764401 | 1.000000 | 0.710497 | 0.572007 |
| CBBCHUSD | 0.186411 | 0.302795 | 0.710497 | 1.000000 | 0.164768 |
| Expected_Inflation | 0.791498 | 0.916008 | 0.572007 | 0.164768 | 1.000000 |
Now that a relationship between crypto prices and expected inflation rates has been established, a deeper dive into the relationship can be performed through an Ordinary Least Squares regression (OLS). The OLS is a strong modeling tool that is often used in econometrics for forecasting future markets.
The purpose of the OLS is to take a theoretical equation: $Y_{i} = {\beta}_{0} + {\beta}_{1}X_{i} + {\beta}_{2}X_{i} + {\beta}_{3}X_{i} + {\beta}_{4}X_{i} + {\epsilon}$ (1.1)
to create the estimated equation: $\hat{Y_{i}} = \hat{\beta}_{0} + \hat{\beta}_{1}X_{i} + \hat{\beta}_{2}X_{i} + \hat{\beta}_{3}X_{i} + \hat{\beta}_{4}X_{i}$ (1.2)
This is achived by minimizing the sum of the squared residuals. In this regression model the expected inflation rate is endogenous, while the crypto prices are exogenous. The output of this model is shown below.
reg = smf.ols(formula = 'Expected_Inflation ~ CBBTCUSD + CBETHUSD + CBLTCUSD + CBBCHUSD', data = FredCryptoDF).fit()
print(reg.summary())
OLS Regression Results
==============================================================================
Dep. Variable: Expected_Inflation R-squared: 0.886
Model: OLS Adj. R-squared: 0.886
Method: Least Squares F-statistic: 2768.
Date: Mon, 07 Mar 2022 Prob (F-statistic): 0.00
Time: 18:21:01 Log-Likelihood: -92.556
No. Observations: 1424 AIC: 195.1
Df Residuals: 1419 BIC: 221.4
Df Model: 4
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 2.7351 0.014 199.518 0.000 2.708 2.762
CBBTCUSD -1.001e-05 1.36e-06 -7.364 0.000 -1.27e-05 -7.34e-06
CBETHUSD 0.0010 1.72e-05 55.684 0.000 0.001 0.001
CBLTCUSD -0.0033 0.000 -10.052 0.000 -0.004 -0.003
CBBCHUSD 9.643e-06 3.38e-05 0.285 0.776 -5.67e-05 7.6e-05
==============================================================================
Omnibus: 18.894 Durbin-Watson: 0.087
Prob(Omnibus): 0.000 Jarque-Bera (JB): 24.036
Skew: 0.179 Prob(JB): 6.03e-06
Kurtosis: 3.526 Cond. No. 4.87e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 4.87e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
From the output, we are able to derive the following model to estimate the effect of the various cryptocurrencies on inflation expectations. The validity of each variable in the model in the model can be interpreted using the standard error and t value of each variable as shown in the output above. The high adjusted R-squared value also seems to suggest that the OLS might be a good fit for the data. Below we will also visualize the estimated model with the real data to do a visual comparison of the estimated expected inflation rates against the real expected inflation rates.
residual = reg.resid #calculates the residuals e for the data
res = pd.DataFrame(residual, columns = ["Residual"])
res["Date"] = FredCryptoDF.DATE
res
| Residual | Date | |
|---|---|---|
| 0 | 0.330277 | 2017-12-20 |
| 1 | 0.351915 | 2017-12-21 |
| 2 | 0.308555 | 2017-12-22 |
| 3 | 0.347427 | 2017-12-23 |
| 4 | 0.328676 | 2017-12-24 |
| ... | ... | ... |
| 1419 | 0.105595 | 2021-11-14 |
| 1420 | 0.101441 | 2021-11-15 |
| 1421 | 0.290537 | 2021-11-16 |
| 1422 | 0.215821 | 2021-11-17 |
| 1423 | 0.369340 | 2021-11-18 |
1424 rows × 2 columns
residual_plot = px.line(res, x = "Date", y = "Residual")
residual_plot.show()
Yhat as shown in equation 1.2 represents the estimated expected inflation values based on the residuals from the OLS model.
Yhat = reg.fittedvalues
Yhat_df = pd.DataFrame(Yhat, columns = ["Predicted Inflation"])
Yhat_df["Residual"] = res.Residual
Yhat_df["Date"] = FredCryptoDF.DATE
Yhat_df["Actual Inflation"] = FredCryptoDF.Expected_Inflation
Yhat_df
| Predicted Inflation | Residual | Date | Actual Inflation | |
|---|---|---|---|---|
| 0 | 2.369723 | 0.330277 | 2017-12-20 | 2.7 |
| 1 | 2.348085 | 0.351915 | 2017-12-21 | 2.7 |
| 2 | 2.391445 | 0.308555 | 2017-12-22 | 2.7 |
| 3 | 2.352573 | 0.347427 | 2017-12-23 | 2.7 |
| 4 | 2.371324 | 0.328676 | 2017-12-24 | 2.7 |
| ... | ... | ... | ... | ... |
| 1419 | 5.594405 | 0.105595 | 2021-11-14 | 5.7 |
| 1420 | 5.598559 | 0.101441 | 2021-11-15 | 5.7 |
| 1421 | 5.409463 | 0.290537 | 2021-11-16 | 5.7 |
| 1422 | 5.484179 | 0.215821 | 2021-11-17 | 5.7 |
| 1423 | 5.330660 | 0.369340 | 2021-11-18 | 5.7 |
1424 rows × 4 columns
Here we plot both the predicted and the actual inflation values to ensure that the predicted model is a good fit for the actual data.
residual_plot = px.line(Yhat_df, x="Date", y = ["Predicted Inflation", "Actual Inflation"])
residual_plot.show()
This graph shows how the change in expected inflation and cryptocurrencies' closing prices correlate. The graph seems to demonstrate that even slight increases in expected inflation correspond to result in a disproportionately large change in the prices of many cryptocurrencies.
FredCryptoPlot = px.line(FredCryptoDF, x = "DATE", y = ["Expected_Inflation", "CBBTCUSD", "CBETHUSD", "CBLTCUSD", "CBBCHUSD"], title = "Visulizing the Movements Each Cryptocurrency & Expected Inflation")
FredCryptoPlot.show()
From the initial exploratory visuals, it was clear that there were some interesting relationships between cryptocurrency prices and expected inflation rates. The OLS linear regression further supports this finding and suggests that the demand for cryptocurrencies increases when there are widespread public fears of rising inflation. More formally we can generalize the model of attractiveness of cryptocurrencies to investors as: $p^{{\beta}}_{i} = {\beta}_{0} + {\beta}_{1}{\alpha}_{i} + {\epsilon}_{i}$
Although the OLS model is a very powerful tool it is weakened when the model does not follow all seven classical assumptions. The time series model does not specifically address the autocorrelation problem which would likely violate the Gauss-Markov theorem for making the OLS the best unbiased linear estimator. To address this an autoregressive integrated moving average algorithm might be useful in developing an even stronger forecasting algorithm. This model is preferred in time series as it uses the previous values from the time series to predict the future values. In other words, ARIMA models use the lag from their own data and the lag from forecasted errors to predict future values.
The auto regressive (AR) part of the model can be described by the follwoing equation: $Y_{t} = {\alpha}+{\beta}_{1}Y_{t-1} + {\beta}_{2}Y_{t-2} + ... + {\beta}_{p}Y_{t-p} + {\epsilon}_{1}$ (2.1)
The moving average (MA) part of the model can be described by the follwoing equation: $Y_{t} = {\alpha} + {\epsilon}_{t} +{\phi}_{1}{\epsilon}_{t-1} + {\phi}_{2}{\epsilon}_{t-2} + ... + {\phi}_{q}{\epsilon}_{t-q}$ (2.2)
Combined this yeilds the (ARIMA) model: $Y_{t} = {\alpha}+{\beta}_{1}Y_{t-1} + {\beta}_{2}Y_{t-2} + ... + {\beta}_{p}Y_{t-p} + {\epsilon}_{1} + {\phi}_{1}{\epsilon}_{t-1} + {\phi}_{2}{\epsilon}_{t-2} + ... + {\phi}_{q}{\epsilon}_{t-q}$ (2.3)
There are 3 terms in the ARIMA model (p, d, q):
d is the number of differences required to make the time series stationary
p is the order of the AR term
q is the order of the MA term
The first step is to calculate the number of differencing operations required to make the time series data stationary. This will be done using the Augmented Dicky Fuller Test(ADF).
Let $H_{0}: $ $d { \neq } 0$ in other words, the time series is non-stationary Then it follows that $H_{{\alpha}}: $ $d = 0$ in other words, the time series is stationary
This test will reject the null if p-value < 0.05 in which case there is no need to find an order of differencing. If the p-value is > 0.05 then we would fail to reject the null and the series will require differencing operations to be performed until the time series is stationary.
# method to test if the time series data is stationary
def ADF_Test(data):
adf_test = adfuller(data, autolag = "AIC")
print(f"ADF: {adf_test[0]}")
print(f"p-value: {adf_test[1]}")
print(f"Number of Lag: {adf_test[2]}")
print(f"Number of Observations: {adf_test[3]}")
print(f"Critical Values:")
for percent, item in adf_test[4].items():
print("\t", percent, ": ", item)
ADF_Test(FredCryptoDF.CBBTCUSD)
ADF_Test(FredCryptoDF.CBBCHUSD)
ADF_Test(FredCryptoDF.CBETHUSD)
ADF_Test(FredCryptoDF.CBLTCUSD)
ADF: 0.16894678038706776 p-value: 0.9704651337999067 Number of Lag: 24 Number of Observations: 1399 Critical Values: 1% : -3.435032872877345 5% : -2.863608153613473 10% : -2.5678710778146954 ADF: -6.7381106010924 p-value: 3.1692891752545215e-09 Number of Lag: 24 Number of Observations: 1399 Critical Values: 1% : -3.435032872877345 5% : -2.863608153613473 10% : -2.5678710778146954 ADF: 1.0561886341025755 p-value: 0.9948248071724336 Number of Lag: 16 Number of Observations: 1407 Critical Values: 1% : -3.4350061979197215 5% : -2.863596381993834 10% : -2.5678648091303056 ADF: -2.272600565958475 p-value: 0.18095713941266384 Number of Lag: 20 Number of Observations: 1403 Critical Values: 1% : -3.435019497302916 5% : -2.863602251005175 10% : -2.567867934524786
Note that the p-values for the first 3 cryptocurrencies are all very high, above 0.05. Additionally, the majority of the critical values are less than the values of their respective Augmented Dicky Fuller test statistic. As a result, we cannot reject the null hypothesis, which leaves us to conclude that the time series data is not stationary.
Intuitively, this makes sense in the context of cryptocurrencies prices and expected inflation rates. This is because changes in crypto prices and inflation expectations are generally speaking the result of mean independent increments that occur to daily economic shocks. These movements in prices depend on the previous price. One method of dealing with this issue is to model the returns of the crypto prices instead of the prices. While daily prices $X_{t}$ are generally non stationary while the daily returns $Y_{t} = \frac{X_{t} - X_{t-1}}{X_{t-1}}$ are generally stationary. To confirm the assumption that price movements are non-stationary we can look at the generalized daily price movements function. $X_{t} = X_{t-1} + {\epsilon}_{t} = X_{t-2} + {\epsilon}_{t-1} + {\epsilon}_{t} + X_{t-3} + {\epsilon}_{t-2} + {\epsilon}_{t} + ... + $ by repeated substitution yeilds: $\sum_{{\tau}=0}^{t} {\epsilon_{\tau}}$ which by definition is a linear stochastic process that has a unit root of 1 which describes a non stationary process. While taking the percent change is a good method to remove this effect another method is to take the log difference of the function. Applying the log difference to the function is useful as logarithms are time-invariant and will help to stabilize the variance. Taking the first order of difference of this function can be used to obtain the required stationary data.
Since the initial ordinary least squares regression model showed that Bitcoin and Ethereum are most likely to have a strong correlation with the expected inflation rates, we will focus our efforts on making those data sets stationery
D is the number of differences required to make the time series stationary. This will be done by ploting the Autocorrelation Function (ACF) and performing the order of difference operation on the data untill the data becomes stationary.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4))
ax1.plot(FredCryptoDF.CBBTCUSD)
ax1.set_title("Original Bitcoin Data")
plot_acf(FredCryptoDF.CBBTCUSD, ax = ax2);
diff = FredCryptoDF.CBBTCUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Once Bitcoin")
plot_acf(diff, ax = ax2);
In the first plot, we can see that there is clear movement of the Bitcoin closing prices over time. Additionally, we see severe autocorrelation for the initial data. The second plot shows the first-order difference of the Bitcoin data. Here we can instantly see that the data is much more stationary than before and the autocorrelation is for the most part in an acceptable range. From these graphs, we can conclude that the value of d, the order of differences required to make the time series stationary in the ARIMA model, is 1 for the first-order difference of the Bitcoin data.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4))
ax1.plot(FredCryptoDF.CBETHUSD)
ax1.set_title("Original Ethereum Data")
plot_acf(FredCryptoDF.CBETHUSD, ax = ax2);
diff = FredCryptoDF.CBETHUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Once Ethereum")
plot_acf(diff, ax = ax2);
diff = FredCryptoDF.CBETHUSD.diff().diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Twice Ethereum")
plot_acf(diff, ax = ax2);
In the first plot, we can see that the Ethereum closing prices are clearly moving in an upwards direction over time and is thus non-stationary. Additionally, we see severe autocorrelation for the initial data. The second plot shows the first-order difference of the Ethereum data. Here the data is much more stationary than before and the autocorrelation is less severe. The third plot shows the second-order difference for the Ethereum data. When compared with the first-order difference we see that the first-order difference is a better fit. From these graphs, we can conclude that the value of d should be 1 for the first-order difference of the Ethereum data.
P is the number of lags to be used in the ARIMA model. This can be determined by creating a Partial Autocorrelation Plot (PACF Plot). Here the partial autocorrelation represents the correlation between the time-series data and its lags.
diff = FredCryptoDF.CBETHUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Once Bitcoin")
ax2.set_ylim(0, 1)
plot_pacf(diff, ax = ax2);
diff = FredCryptoDF.CBETHUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Once Ethereum")
ax2.set_ylim(0, 1)
plot_pacf(diff, ax = ax2);
From both PACF plots it is clear that the first term in the data that displays significant lag is point 6. Thus the q value for the AMIRA model for both Bitcoin and Ethereum is 6.
Q is the order of the moving average term to be used in the ARIMA model. This refers to the number of lagged forecast errors that should be taken into account in the model. The ACF plot will show the number of lags to consider.
diff = FredCryptoDF.CBBTCUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax2.set_ylim(0, 1)
ax1.set_title("Difference Once Bitcoin")
plot_acf(diff, ax = ax2);
diff = FredCryptoDF.CBETHUSD.diff().dropna()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(diff)
ax1.set_title("Difference Once Ethereum")
ax2.set_ylim(0, 1)
plot_acf(diff, ax = ax2);
From the plots above, we can determine that number of lagged forecast errors for Bitcoin is 4 and the number of errors for Ethereum is 3.
model = ARIMA(FredCryptoDF.CBBTCUSD, order = (6,1,4)) #ARIMA model for Bitcoin
result_BTC = model.fit(disp = 0)
print(result_BTC.summary())
/Users/eshankaul/opt/anaconda3/lib/python3.8/site-packages/statsmodels/tsa/arima_model.py:472: FutureWarning:
statsmodels.tsa.arima_model.ARMA and statsmodels.tsa.arima_model.ARIMA have
been deprecated in favor of statsmodels.tsa.arima.model.ARIMA (note the .
between arima and model) and
statsmodels.tsa.SARIMAX. These will be removed after the 0.12 release.
statsmodels.tsa.arima.model.ARIMA makes use of the statespace framework and
is both well tested and maintained.
To silence this warning and continue using ARMA and ARIMA until they are
removed, use:
import warnings
warnings.filterwarnings('ignore', 'statsmodels.tsa.arima_model.ARMA',
FutureWarning)
warnings.filterwarnings('ignore', 'statsmodels.tsa.arima_model.ARIMA',
FutureWarning)
ARIMA Model Results
==============================================================================
Dep. Variable: D.CBBTCUSD No. Observations: 1423
Model: ARIMA(6, 1, 4) Log Likelihood -11793.207
Method: css-mle S.D. of innovations 961.064
Date: Mon, 07 Mar 2022 AIC 23610.415
Time: 18:21:11 BIC 23673.541
Sample: 1 HQIC 23633.993
====================================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------------
const 27.6949 27.141 1.020 0.308 -25.501 80.891
ar.L1.D.CBBTCUSD 0.0468 0.099 0.471 0.637 -0.148 0.242
ar.L2.D.CBBTCUSD -1.4398 0.097 -14.871 0.000 -1.630 -1.250
ar.L3.D.CBBTCUSD 0.1316 0.116 1.136 0.256 -0.095 0.359
ar.L4.D.CBBTCUSD -0.6316 0.104 -6.072 0.000 -0.836 -0.428
ar.L5.D.CBBTCUSD 0.0238 0.031 0.780 0.435 -0.036 0.084
ar.L6.D.CBBTCUSD 0.0895 0.030 2.977 0.003 0.031 0.148
ma.L1.D.CBBTCUSD -0.0874 0.097 -0.898 0.369 -0.278 0.103
ma.L2.D.CBBTCUSD 1.4988 0.094 16.026 0.000 1.315 1.682
ma.L3.D.CBBTCUSD -0.1867 0.099 -1.885 0.059 -0.381 0.007
ma.L4.D.CBBTCUSD 0.7370 0.087 8.437 0.000 0.566 0.908
Roots
=============================================================================
Real Imaginary Modulus Frequency
-----------------------------------------------------------------------------
AR.1 -0.2549 -0.9866j 1.0190 -0.2902
AR.2 -0.2549 +0.9866j 1.0190 0.2902
AR.3 0.2992 -1.0542j 1.0958 -0.2060
AR.4 0.2992 +1.0542j 1.0958 0.2060
AR.5 2.8212 -0.0000j 2.8212 -0.0000
AR.6 -3.1756 -0.0000j 3.1756 -0.5000
MA.1 -0.2251 -0.9845j 1.0099 -0.2858
MA.2 -0.2251 +0.9845j 1.0099 0.2858
MA.3 0.3517 -1.0985j 1.1534 -0.2007
MA.4 0.3517 +1.0985j 1.1534 0.2007
-----------------------------------------------------------------------------
The model above shows the results from the ARIMA model on the Bitcoin data. The plots below show that the data is indeed stationary, and the data is distributed around the mean which confirms the stationary nature of the data.
residuals_BTC = pd.DataFrame(result_BTC.resid)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(residuals_BTC)
ax2.hist(residuals_BTC, density = True)
(array([1.48281335e-06, 2.47135559e-06, 7.90833789e-06, 3.41047071e-05,
5.17007589e-04, 1.13682357e-04, 1.87823025e-05, 7.41406677e-06,
0.00000000e+00, 4.94271118e-07]),
array([-6801.31129456, -5379.53959234, -3957.76789012, -2535.9961879 ,
-1114.22448568, 307.54721654, 1729.31891876, 3151.09062098,
4572.8623232 , 5994.63402542, 7416.40572764]),
<BarContainer object of 10 artists>)
Based on the results from the Bitcoin ARIMA model we can now plot the forecasted model against the actual closing price movements. The ARIMA model shows a much greater fit then the original OLS model that was used before.
fig = result_BTC.plot_predict(start = 1, end = 1423, dynamic = False);
plt.title("Plot of Forecasted and Real Bitcoin Prices between 2017-12-21 and 2021-10-26")
plt.xlabel("Date") # 1 = 2017-12-21 200 = 2019-01-29 800 = 2020-03-04 1200 = 2021-04-09 1400 = 2021-10-26
plt.ylabel("Close Price")
plt.show()
print(f"date 1 is: {FredCryptoDF.DATE[1]}")
print(f"date 200 is: {FredCryptoDF.DATE[200]}")
print(f"date 400 is: {FredCryptoDF.DATE[400]}")
print(f"date 600 is: {FredCryptoDF.DATE[600]}")
print(f"date 800 is: {FredCryptoDF.DATE[800]}")
print(f"date 1000 is: {FredCryptoDF.DATE[1000]}")
print(f"date 1200 is: {FredCryptoDF.DATE[1200]}")
print(f"date 1400 is: {FredCryptoDF.DATE[1400]}")
date 1 is: 2017-12-21 00:00:00 date 200 is: 2018-07-08 00:00:00 date 400 is: 2019-01-29 00:00:00 date 600 is: 2019-08-17 00:00:00 date 800 is: 2020-03-04 00:00:00 date 1000 is: 2020-09-21 00:00:00 date 1200 is: 2021-04-09 00:00:00 date 1400 is: 2021-10-26 00:00:00
model = ARIMA(FredCryptoDF.CBETHUSD, order = (6,1,3)) #ARIMA model for Ethereum
result_ETH = model.fit(disp = 0)
print(result_ETH.summary())
/Users/eshankaul/opt/anaconda3/lib/python3.8/site-packages/statsmodels/tsa/arima_model.py:472: FutureWarning:
statsmodels.tsa.arima_model.ARMA and statsmodels.tsa.arima_model.ARIMA have
been deprecated in favor of statsmodels.tsa.arima.model.ARIMA (note the .
between arima and model) and
statsmodels.tsa.SARIMAX. These will be removed after the 0.12 release.
statsmodels.tsa.arima.model.ARIMA makes use of the statespace framework and
is both well tested and maintained.
To silence this warning and continue using ARMA and ARIMA until they are
removed, use:
import warnings
warnings.filterwarnings('ignore', 'statsmodels.tsa.arima_model.ARMA',
FutureWarning)
warnings.filterwarnings('ignore', 'statsmodels.tsa.arima_model.ARIMA',
FutureWarning)
ARIMA Model Results
==============================================================================
Dep. Variable: D.CBETHUSD No. Observations: 1423
Model: ARIMA(6, 1, 3) Log Likelihood -8080.999
Method: css-mle S.D. of innovations 70.795
Date: Mon, 07 Mar 2022 AIC 16183.999
Time: 18:21:15 BIC 16241.864
Sample: 1 HQIC 16205.613
====================================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------------
const 2.2005 2.035 1.081 0.279 -1.788 6.189
ar.L1.D.CBETHUSD -0.4681 0.196 -2.385 0.017 -0.853 -0.083
ar.L2.D.CBETHUSD -0.8034 0.085 -9.403 0.000 -0.971 -0.636
ar.L3.D.CBETHUSD -0.2406 0.196 -1.225 0.221 -0.625 0.144
ar.L4.D.CBETHUSD 0.0925 0.039 2.348 0.019 0.015 0.170
ar.L5.D.CBETHUSD 0.0080 0.033 0.240 0.810 -0.057 0.073
ar.L6.D.CBETHUSD 0.1527 0.031 4.850 0.000 0.091 0.214
ma.L1.D.CBETHUSD 0.3887 0.198 1.960 0.050 4.5e-05 0.777
ma.L2.D.CBETHUSD 0.8306 0.069 12.116 0.000 0.696 0.965
ma.L3.D.CBETHUSD 0.2302 0.204 1.128 0.259 -0.170 0.630
Roots
=============================================================================
Real Imaginary Modulus Frequency
-----------------------------------------------------------------------------
AR.1 -1.3596 -0.0000j 1.3596 -0.5000
AR.2 1.7650 -0.0000j 1.7650 -0.0000
AR.3 -0.3194 -1.2160j 1.2572 -0.2909
AR.4 -0.3194 +1.2160j 1.2572 0.2909
AR.5 0.0906 -1.3108j 1.3139 -0.2390
AR.6 0.0906 +1.3108j 1.3139 0.2390
MA.1 -0.0633 -1.1152j 1.1170 -0.2590
MA.2 -0.0633 +1.1152j 1.1170 0.2590
MA.3 -3.4814 -0.0000j 3.4814 -0.5000
-----------------------------------------------------------------------------
residuals_ETH = pd.DataFrame(result_ETH.resid)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16, 4))
ax1.plot(residuals_ETH)
ax2.hist(residuals_ETH, density = True)
(array([5.50379803e-06, 0.00000000e+00, 5.50379803e-06, 3.85265862e-05,
1.21083557e-04, 8.64096291e-04, 6.38990952e-03, 3.24724084e-04,
5.50379803e-05, 2.75189902e-05]),
array([-794.24171143, -666.55884872, -538.875986 , -411.19312329,
-283.51026058, -155.82739787, -28.14453516, 99.53832755,
227.22119026, 354.90405297, 482.58691568]),
<BarContainer object of 10 artists>)
fig = result_ETH.plot_predict(start = 1, end = 1423, dynamic = False);
plt.title("Plot of Forecasted and Real Ethereum Prices between 2017-12-21 and 2021-10-26")
plt.xlabel("Date") # 1 = 2017-12-21 200 = 2019-01-29 800 = 2020-03-04 1200 = 2021-04-09 1400 = 2021-10-26
plt.ylabel("Close Price")
plt.show()
print(f"date 1 is: {FredCryptoDF.DATE[1]}")
print(f"date 200 is: {FredCryptoDF.DATE[200]}")
print(f"date 400 is: {FredCryptoDF.DATE[400]}")
print(f"date 600 is: {FredCryptoDF.DATE[600]}")
print(f"date 800 is: {FredCryptoDF.DATE[800]}")
print(f"date 1000 is: {FredCryptoDF.DATE[1000]}")
print(f"date 1200 is: {FredCryptoDF.DATE[1200]}")
print(f"date 1400 is: {FredCryptoDF.DATE[1400]}")
date 1 is: 2017-12-21 00:00:00 date 200 is: 2018-07-08 00:00:00 date 400 is: 2019-01-29 00:00:00 date 600 is: 2019-08-17 00:00:00 date 800 is: 2020-03-04 00:00:00 date 1000 is: 2020-09-21 00:00:00 date 1200 is: 2021-04-09 00:00:00 date 1400 is: 2021-10-26 00:00:00
Based on the results from the Ethereum ARIMA model we can now plot the forecasted model against the actual closing price movements. From this visual, we can observe that the ARIMA model is a good fit for the real Ethereum data over this time period. This type of model might be useful to crypto investors in making their predictions on how the price of the cryptocurrency will move over time to optimize their strategy.
To predict the next n samples of Ethereum prices we can use the .forcast(steps = n) method which will return an array of the next n predictions of Ethereum closing prices based off the ARIMA model.
result_ETH.forecast(steps = 100)[0]
array([4012.58716569, 3984.57695835, 4000.73647768, 3942.67926619,
3977.9744621 , 3963.91218661, 3962.76432084, 3961.5560706 ,
3976.66869338, 3965.92534116, 3969.24644909, 3975.38876529,
3978.61435399, 3975.28329434, 3980.2737222 , 3983.76244813,
3984.74690392, 3985.90884531, 3989.63316421, 3991.54398744,
3993.2296392 , 3995.6282382 , 3998.16637848, 4000.00033205,
4002.23632275, 4004.60348936, 4006.73989457, 4008.82704204,
4011.14397496, 4013.35623583, 4015.48583321, 4017.6965671 ,
4019.94654209, 4022.11747705, 4024.30097418, 4026.52351164,
4028.72835205, 4030.91248043, 4033.11765396, 4035.32551505,
4037.52078629, 4039.71863311, 4041.92382161, 4044.1237866 ,
4046.32174943, 4048.52362797, 4050.72531593, 4052.92439754,
4055.12480452, 4057.32627946, 4059.52652459, 4061.72652387,
4063.92744205, 4066.12813482, 4068.32835116, 4070.52888108,
4072.72959644, 4074.93003662, 4077.13047565, 4079.33108246,
4081.53162477, 4083.73208666, 4085.93262366, 4088.13317913,
4090.33368014, 4092.53419141, 4094.73473364, 4096.93525626,
4099.13576731, 4101.33629541, 4103.53682418, 4105.73734171,
4107.93786337, 4110.13839045, 4112.33891281, 4114.5394336 ,
4116.73995801, 4118.94048194, 4121.1410038 , 4123.34152679,
4125.54205063, 4127.74257341, 4129.94309609, 4132.14361948,
4134.34414264, 4136.54466544, 4138.74518854, 4140.94571174,
4143.14623472, 4145.34675771, 4147.54728085, 4149.74780391,
4151.94832692, 4154.14884999, 4156.34937308, 4158.54989611,
4160.75041916, 4162.95094224, 4165.15146529, 4167.35198834])
The goal of the project was to determine if there was any validity to the argument that cryptocurrency prices are correlated with inflation rates. To establish if there was a relationship between cryptocurrency prices and expected inflation rates a Pearson correlation and an Ordinary Least Squares regression were performed on expected inflation rates and the closing prices of four different cryptocurrency prices. The results from the initial analysis seem to confirm that a linear relationship between the prices of cryptocurrencies and inflation rates is positively correlated. In other words, as the prices of cryptocurrencies increase the models suggest that the public's expected inflation rate also increases. After discovering this relationship, the next objective of the project was to determine if there was any useful method of determining if an investor could determine the future prices of various cryptocurrencies. There are many issues with attempting to predict future prices in a time-series model. These issues are addressed by using an autoregressive moving average that will make the time-series data stationary and use the model's estimated forecast errors to improve the model. This model was done on Bitcoin and Ethereum data to determine if investors could generate some level of alpha, some statistical edge, to predict the future prices of these two cryptocurrencies. The results from these tests suggest that the generated model is a good fit for the current data and is likely useful for investors to be used in their analysis when attempting to determine how to hedge their investments regarding cryptocurrencies.
https://quant.stackexchange.com/questions/16481/why-do-we-usually-model-returns-and-not-prices https://quant.stackexchange.com/questions/4160/discrete-returns-versus-log-returns-of-assets https://www.emerald.com/insight/content/doi/10.1108/SEF-09-2012-0106/full/html https://stats.stackexchange.com/questions/465514/why-prices-are-usually-not-stationary-but-returns-are-more-likely-to-be-station https://en.wikipedia.org/wiki/Unit_root https://otexts.com/fpp2/stationarity.html https://blog.quantinsti.com/stationarity/ https://link.springer.com/article/10.1007/s00521-020-05129-6 https://www.semanticscholar.org/paper/Time-series-forecast-in-non-stationary-environment-Garbacz/f79fb84f5001dafe120c68ae7379f92907566511 https://www.semanticscholar.org/paper/Time-series-forecast-in-non-stationary-environment-Garbacz/f79fb84f5001dafe120c68ae7379f92907566511
https://en.wikipedia.org/wiki/Augmented_Dickey%E2%80%93Fuller_test https://en.wikipedia.org/wiki/Pearson_correlation_coefficient https://en.wikipedia.org/wiki/Ordinary_least_squares https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average